const canvas = document.getElementById("gomoku-board");
const ctx = canvas.getContext("2d");
const resetButton = document.getElementById("reset-button");
const undoButton = document.getElementById("undo-button");
const currentPlayerSpan = document.getElementById("current-player");
const statusMessage = document.getElementById("status-message");
const timerDisplay = document.getElementById("turn-timer");

const BOARD_SIZE = 15;
const PADDING = 20;
const CELL_SIZE = (canvas.width - PADDING * 2) / (BOARD_SIZE - 1);
const GRID_START = PADDING;
const GRID_END = canvas.width - PADDING;
const TURN_TIME_SECONDS = 30;
const STAR_POINTS = [
  [3, 3],
  [11, 3],
  [7, 7],
  [3, 11],
  [11, 11],
];

let board = [];
let currentPlayer = 1;
let lastMove = null;
let gameOver = false;
let moveHistory = [];
let timerInterval = null;
let timeRemaining = TURN_TIME_SECONDS;

function initGame() {
  board = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0));
  currentPlayer = 1;
  lastMove = null;
  gameOver = false;
  moveHistory = [];
  setCurrentPlayerIndicator(currentPlayer);
  setStatusMessage("黑方先行，加油！");
  updateUndoButtonState();
  render();
  startTurnTimer();
}

function render() {
  drawBoard();
  drawPieces();
  drawLastMoveMarker();
}

function drawBoard() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "#dcb46d";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  ctx.strokeStyle = "#333";
  ctx.lineWidth = 1;
  ctx.beginPath();
  for (let i = 0; i < BOARD_SIZE; i++) {
    const pos = GRID_START + i * CELL_SIZE;
    ctx.moveTo(GRID_START, pos);
    ctx.lineTo(GRID_END, pos);
    ctx.moveTo(pos, GRID_START);
    ctx.lineTo(pos, GRID_END);
  }
  ctx.stroke();

  ctx.fillStyle = "#333";
  STAR_POINTS.forEach(([x, y]) => {
    ctx.beginPath();
    ctx.arc(
      GRID_START + x * CELL_SIZE,
      GRID_START + y * CELL_SIZE,
      4,
      0,
      Math.PI * 2
    );
    ctx.fill();
  });
}

function drawPieces() {
  board.forEach((row, y) => {
    row.forEach((cell, x) => {
      if (!cell) return;
      const centerX = GRID_START + x * CELL_SIZE;
      const centerY = GRID_START + y * CELL_SIZE;
      const gradient = ctx.createRadialGradient(
        centerX - 5,
        centerY - 5,
        4,
        centerX,
        centerY,
        CELL_SIZE / 2 - 4
      );

      if (cell === 1) {
        gradient.addColorStop(0, "#4a4a4a");
        gradient.addColorStop(1, "#000");
      } else {
        gradient.addColorStop(0, "#fff");
        gradient.addColorStop(1, "#d4d4d4");
      }

      ctx.beginPath();
      ctx.fillStyle = gradient;
      ctx.arc(centerX, centerY, CELL_SIZE / 2 - 6, 0, Math.PI * 2);
      ctx.fill();
      ctx.closePath();
    });
  });
}

function drawLastMoveMarker() {
  if (!lastMove) return;
  const { x, y } = lastMove;
  const centerX = GRID_START + x * CELL_SIZE;
  const centerY = GRID_START + y * CELL_SIZE;

  ctx.beginPath();
  ctx.strokeStyle = "#ff7043";
  ctx.lineWidth = 2;
  ctx.arc(centerX, centerY, 6, 0, Math.PI * 2);
  ctx.stroke();
  ctx.closePath();
}

function handleBoardClick(event) {
  if (gameOver) return;

  const location = translateToBoardCoordinates(event);
  if (!location) return;

  const { x, y } = location;
  if (board[y][x] !== 0) {
    setStatusMessage("该位置已有棋子，请换一个交叉点。");
    return;
  }

  stopTurnTimer();
  board[y][x] = currentPlayer;
  lastMove = { x, y, player: currentPlayer };
  recordMove(x, y, currentPlayer);
  render();

  if (checkWin(x, y)) {
    gameOver = true;
    const winnerName = currentPlayer === 1 ? "黑方" : "白方";
    setCurrentPlayerIndicator(currentPlayer);
    setStatusMessage(`${winnerName}获胜，恭喜！`);
    stopTurnTimer();
    return;
  }

  if (isBoardFull()) {
    gameOver = true;
    setCurrentPlayerIndicator(null);
    setStatusMessage("棋局结束，双方战成平手。");
    stopTurnTimer();
    return;
  }

  currentPlayer = currentPlayer === 1 ? 2 : 1;
  setCurrentPlayerIndicator(currentPlayer);
  setStatusMessage(`${currentPlayer === 1 ? "黑方" : "白方"}请落子。`);
  startTurnTimer();
}

canvas.addEventListener("click", handleBoardClick);
resetButton.addEventListener("click", initGame);
undoButton.addEventListener("click", undoLastMove);

function recordMove(x, y, player) {
  moveHistory.push({
    moveNumber: moveHistory.length + 1,
    player,
    x,
    y,
  });
  updateUndoButtonState();
}

function updateUndoButtonState() {
  undoButton.disabled = moveHistory.length === 0;
}

function undoLastMove() {
  if (moveHistory.length === 0) return;

  stopTurnTimer();
  const lastRecord = moveHistory.pop();
  board[lastRecord.y][lastRecord.x] = 0;
  currentPlayer = lastRecord.player;
  gameOver = false;
  lastMove = moveHistory.length
    ? {
        x: moveHistory[moveHistory.length - 1].x,
        y: moveHistory[moveHistory.length - 1].y,
        player: moveHistory[moveHistory.length - 1].player,
      }
    : null;

  setCurrentPlayerIndicator(currentPlayer);
  setStatusMessage(`${currentPlayer === 1 ? "黑方" : "白方"}请落子。`);
  updateUndoButtonState();
  render();
  startTurnTimer();
}

function translateToBoardCoordinates(event) {
  const rect = canvas.getBoundingClientRect();
  const scaleX = canvas.width / rect.width;
  const scaleY = canvas.height / rect.height;
  const canvasX = (event.clientX - rect.left) * scaleX;
  const canvasY = (event.clientY - rect.top) * scaleY;

  const boardX = Math.round((canvasX - GRID_START) / CELL_SIZE);
  const boardY = Math.round((canvasY - GRID_START) / CELL_SIZE);

  if (boardX < 0 || boardX >= BOARD_SIZE || boardY < 0 || boardY >= BOARD_SIZE) {
    return null;
  }

  const snapX = GRID_START + boardX * CELL_SIZE;
  const snapY = GRID_START + boardY * CELL_SIZE;
  const distance = Math.hypot(canvasX - snapX, canvasY - snapY);

  if (distance > CELL_SIZE * 0.45) {
    return null;
  }

  return { x: boardX, y: boardY };
}

function checkWin(x, y) {
  const player = board[y][x];
  if (!player) return false;

  const directions = [
    [1, 0],
    [0, 1],
    [1, 1],
    [1, -1],
  ];

  return directions.some(([dx, dy]) => {
    let count = 1;
    count += countInDirection(x, y, dx, dy, player);
    count += countInDirection(x, y, -dx, -dy, player);
    return count >= 5;
  });
}

function countInDirection(x, y, dx, dy, player) {
  let count = 0;
  let nextX = x + dx;
  let nextY = y + dy;

  while (
    nextX >= 0 &&
    nextX < BOARD_SIZE &&
    nextY >= 0 &&
    nextY < BOARD_SIZE &&
    board[nextY][nextX] === player
  ) {
    count++;
    nextX += dx;
    nextY += dy;
  }

  return count;
}

function isBoardFull() {
  return board.every((row) => row.every((cell) => cell !== 0));
}

function setCurrentPlayerIndicator(player) {
  currentPlayerSpan.classList.remove("player-black", "player-white");
  if (player === 1) {
    currentPlayerSpan.textContent = "黑方";
    currentPlayerSpan.classList.add("player-black");
  } else if (player === 2) {
    currentPlayerSpan.textContent = "白方";
    currentPlayerSpan.classList.add("player-white");
  } else {
    currentPlayerSpan.textContent = "—";
  }
}

function setStatusMessage(message) {
  statusMessage.textContent = message;
}

function startTurnTimer() {
  stopTurnTimer();
  timeRemaining = TURN_TIME_SECONDS;
  updateTimerDisplay();
  timerInterval = setInterval(() => {
    timeRemaining -= 1;
    if (timeRemaining <= 0) {
      stopTurnTimer();
      timeRemaining = 0;
      updateTimerDisplay();
      handleTimeout();
    } else {
      updateTimerDisplay();
    }
  }, 1000);
}

function stopTurnTimer() {
  if (timerInterval) {
    clearInterval(timerInterval);
    timerInterval = null;
  }
}

function updateTimerDisplay() {
  timerDisplay.textContent = String(Math.max(timeRemaining, 0));
  if (timeRemaining <= 5) {
    timerDisplay.classList.add("timer-danger");
  } else {
    timerDisplay.classList.remove("timer-danger");
  }
}

function handleTimeout() {
  if (gameOver) return;
  gameOver = true;
  const winner = currentPlayer === 1 ? 2 : 1;
  const loserName = currentPlayer === 1 ? "黑方" : "白方";
  const winnerName = winner === 1 ? "黑方" : "白方";
  setCurrentPlayerIndicator(winner);
  setStatusMessage(`${loserName}超时，${winnerName}获胜！`);
  updateUndoButtonState();
}

initGame();
